package com.jin.webvideo.config.filter.access;

import com.jin.webvideo.base.SpringBeanGetter;
import com.jin.webvideo.base.util.ObjectInitializer;
import com.jin.webvideo.base.util.ObjectPool;
import com.jin.webvideo.config.filter.access.handler.AccessHandler;
import com.jin.webvideo.config.filter.access.handler.ListHandlerChain;
import com.jin.webvideo.entity.SessionStore;
import lombok.Getter;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class AccessControl {
    public class Access {
        @Getter
        private boolean allow = true;
        @Getter
        private String information;
        @Getter
        private int httpCode = 200;
        public static void forbid(Access access, int httpCode, String information) {
            access.allow = false;
            access.httpCode = httpCode;
            access.information = information;
        }
    }

    private volatile static AccessControl control;
    public static AccessControl getInstance() {
        if (control == null) {
            synchronized (AccessControl.class) {
                if (null == control) {
                    control = new AccessControl();
                    Collection<AccessHandler> c = SpringBeanGetter.getBeansOfType(AccessHandler.class).values();
                    control.setHandlers(new ArrayList<>(c));
                }
            }
        }
        return control;
    }

    private final Access Default = new Access();
    // 对象池
    private ObjectPool<Access> pool;
    private List<AccessHandler> handlers;
    private AccessControl() {
        pool = new ObjectPool<>(128, new ObjectInitializer<Access>() {
            @Override
            public Access create(ObjectPool<Access> pool) {
                return new Access();
            }

            @Override
            public boolean initialize(Access obj) {
                obj.allow = true;
                return true;
            }
        });
        handlers = new ArrayList<>();
    }

    public void recycle(Access access) {
        pool.recycle(access);
    }

    public void register(AccessHandler handler) {
        int idx = 0;
        for (int i = 0, l = handlers.size(); i < l; i ++) {
            if (handlers.get(i).order() > handler.order()) {
                idx = i;
                break;
            }
        }
        handlers.add(idx, handler);
    }

    public Access chkAccess(SessionStore store, HttpServletRequest request) {
        try {
            Access access = pool.get();
            new ListHandlerChain(handlers).doHandle(access, GlobalImpl.GLOBAL, request, store);
            return access;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return Default;
    }

    protected void setHandlers(List<AccessHandler> handlers) {
        //
        handlers.sort((o1, o2) -> o1.order() == o2.order()?0:(o1.order() > o2.order()?1:-1));
        this.handlers = handlers;
    }
}
